package com.whcoding.easypoi.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.usermodel.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @program: spring-boot-learning
 * @description:
 * @author: whcoding
 * @create: 2022-09-08 16:17
 **/
public class ExportExcelUtils {

	public static <T> void exportExcel(HttpServletResponse response, LinkedHashMap<String, String> headAlias, List<T> result, String fileName) throws IllegalAccessException, IOException {
		// 创建excel工作簿 SXSSFWorkbook 是专门用于大数据了的导出　　
		XSSFWorkbook wb = new XSSFWorkbook();
		// 创建sheet
		XSSFSheet sheet = wb.createSheet();
		//设置内容样式
		XSSFCellStyle style = wb.createCellStyle();
		// 设置单元格内容水平对其方式 居中对齐
		style.setAlignment(HorizontalAlignment.CENTER);
		// 设置单元格内容垂直对其方式
		style.setVerticalAlignment(VerticalAlignment.CENTER);
		// 创建字体对象
		XSSFFont font = wb.createFont();

		//设置Excel标题
		//标题别名设置为null，则按照实体属性全量导出
		//标题别名为null result一定不能为null 否则导出空Excel
		if (null != result && result.size() > 0) {
			T entity = result.get(0);
			Class c = entity.getClass();
			Field[] fs = c.getDeclaredFields();
			if (null == headAlias || headAlias.size() == 0) {
				headAlias = new LinkedHashMap<>();
				for (int i = 0; i < fs.length; i++) {
					//类中的成员变量为private,故必须进行此操作
					fs[i].setAccessible(true);
					headAlias.put(fs[i].getName(), "");
				}
			}
		}
		// 设置sheet为文本格式
		XSSFDataFormat dataFormat = wb.createDataFormat();
		style.setDataFormat(dataFormat.getFormat("@"));

		// 全表头处理
		if (null != headAlias && headAlias.size() > 0) {
			//字体加粗
			font.setBold(true);
			style.setFont(font);
			// 手动设置列宽。第一个参数表示要为第几列设；，第二个参数表示列的宽度，n为列高的像素数。
			for (int i = 0; i < headAlias.size(); i++) {
				sheet.setColumnWidth(i, (short) (35.7 * 300));
				sheet.setDefaultColumnStyle(i, style);
			}
			// 创建第一行
			XSSFRow row = sheet.createRow(0);
			int i = 0;
			//设置标题内容，有别名显示别名
			for (Map.Entry<String, String> entry : headAlias.entrySet()) {
				if (i < headAlias.size()) {
					XSSFCell cell = row.createCell(i);
					if (StringUtils.isEmpty(entry.getValue())) {
						cell.setCellValue(entry.getKey());
					} else {
						cell.setCellValue(entry.getValue());
					}
					cell.setCellStyle(style);
				}
				i++;
			}
		}
		// 设置Excel内容
		if (null != result && result.size() > 0) {
			//字体不加粗
			font.setBold(false);
			style.setFont(font);
			XSSFDataFormat df = wb.createDataFormat();
			style.setDataFormat(df.getFormat("0.00"));
			//将List<T> 转换为 List<Map<String,Object>>
			List<Map<String, Object>> list = beanToMapList(result);

			for (int i = 0; i < list.size(); i++) {
				// Row 行,Cell 方格 , Row 和 Cell 都是从0开始计数的
				// 创建一行，在页sheet上
				// 内容行从1开始 0行为表头
				XSSFRow row = sheet.createRow(i + 1);
				// 在row行上创建一个方格
				int j = 0;
				for (Map.Entry<String, String> entry : headAlias.entrySet()) {
					String key = entry.getKey();
					XSSFCell cell = row.createCell(j);
					Object object = list.get(i).get(key);
					if ("createdAt".equals(key) || "modifiedAt".equals(key)) {
						if (null != object) {
							SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
							String dateStr = sdf.format((Date) object);
							cell.setCellValue(dateStr);
						}
					} else if ("taxAmount".equals(key) || "taxPrice".equals(key)
							|| "price".equals(key) || "taxRate".equals(key)) {
						if (object != null) {
							BigDecimal bigDecimal = new BigDecimal(object.toString());
							Double doubleVal = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
							cell.setCellValue(doubleVal);
							cell.setCellStyle(style);
						}
					} else {
						cell.setCellValue(object == null ? "" : object.toString());
					}
					j++;
				}
			}
		}
		// ----------- Excel创建完成 ---------------
		// 开始设定下载参数
		fileName = new String(java.net.URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
		// 如果文件名是英文名不需要加编码格式，如果是中文名需要添加"iso-8859-1"防止乱码
		response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
		response.setContentType("application/vnd.ms-excel;charset=utf-8");
		// 开始处理下载的流
		OutputStream out = response.getOutputStream();
		wb.write(out);
		out.flush();
		wb.close();
		if (out != null) {
			out.close();
		}
	}

	/**
	 * Bean转为map
	 *
	 * @param list
	 * @param <T>
	 * @return
	 * @throws IllegalAccessException
	 */
	private static <T> List<Map<String, Object>> beanToMapList(List<T> list) throws IllegalAccessException {
		List<Map<String, Object>> result = new ArrayList<>();
		for (T entity : list) {
			Class c = entity.getClass();
			Field[] fs = FieldUtils.getAllFields(c);
			Map<String, Object> field = new LinkedHashMap<>();
			for (Field f : fs) {
				f.setAccessible(true);
				field.put(f.getName(), f.get(entity));
			}
			result.add(field);
		}
		return result;
	}

}
